//! # 测试辅助工具
//! 
//! 提供集成测试所需的辅助函数和模拟对象

use rustcloud::prelude::*;
use std::sync::Arc;
use std::collections::HashMap;
use tokio::sync::RwLock;

/// 模拟服务实例
pub fn create_mock_service_instance(name: &str, host: &str, port: u16) -> ServiceInstance {
    ServiceInstance {
        service_id: format!("{}-{}", name, uuid::Uuid::new_v4()),
        host: host.to_string(),
        port,
        scheme: "http".to_string(),
        metadata: {
            let mut map = HashMap::new();
            map.insert("service_name".to_string(), name.to_string());
            map.insert("version".to_string(), "1.0.0".to_string());
            map
        },
        healthy: true,
        weight: 1.0,
        group: None,
        namespace: None,
        environment: Some("test".to_string()),
        cluster: None,
    }
}

/// 模拟HTTP服务器
pub struct MockHttpServer {
    pub port: u16,
    pub responses: Arc<RwLock<HashMap<String, String>>>,
}

impl MockHttpServer {
    pub fn new(port: u16) -> Self {
        Self {
            port,
            responses: Arc::new(RwLock::new(HashMap::new())),
        }
    }

    pub async fn add_response(&self, path: &str, response: &str) {
        let mut responses = self.responses.write().await;
        responses.insert(path.to_string(), response.to_string());
    }

    pub async fn start(&self) -> Result<(), Box<dyn std::error::Error>> {
        let responses = self.responses.clone();
        
        let app = axum::Router::new()
            .route("/*path", axum::routing::get(move |path: axum::extract::Path<String>| {
                let responses = responses.clone();
                async move {
                    let responses = responses.read().await;
                    if let Some(response) = responses.get(&path) {
                        axum::response::Html(response.clone())
                    } else {
                        axum::response::Html("Not Found".to_string())
                    }
                }
            }))
            .route("/health", axum::routing::get(|| async {
                axum::Json(serde_json::json!({
                    "status": "UP",
                    "timestamp": chrono::Utc::now().to_rfc3339()
                }))
            }));

        let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{}", self.port)).await?;
        
        tokio::spawn(async move {
            axum::serve(listener, app).await.unwrap();
        });

        // 等待服务器启动
        tokio::time::sleep(std::time::Duration::from_millis(100)).await;
        
        Ok(())
    }
}

/// 测试指标收集器
pub struct TestMetricsCollector {
    counters: Arc<RwLock<HashMap<String, f64>>>,
    gauges: Arc<RwLock<HashMap<String, f64>>>,
    histograms: Arc<RwLock<HashMap<String, Vec<f64>>>>,
}

impl TestMetricsCollector {
    pub fn new() -> Self {
        Self {
            counters: Arc::new(RwLock::new(HashMap::new())),
            gauges: Arc::new(RwLock::new(HashMap::new())),
            histograms: Arc::new(RwLock::new(HashMap::new())),
        }
    }

    pub async fn get_counter(&self, name: &str) -> Option<f64> {
        let counters = self.counters.read().await;
        counters.get(name).copied()
    }

    pub async fn get_gauge(&self, name: &str) -> Option<f64> {
        let gauges = self.gauges.read().await;
        gauges.get(name).copied()
    }

    pub async fn get_histogram_values(&self, name: &str) -> Option<Vec<f64>> {
        let histograms = self.histograms.read().await;
        histograms.get(name).cloned()
    }
}

#[async_trait::async_trait]
impl MetricsCollector for TestMetricsCollector {
    async fn record_counter(&self, name: &str, value: f64, _labels: Labels) -> ServiceResult<()> {
        let mut counters = self.counters.write().await;
        *counters.entry(name.to_string()).or_insert(0.0) += value;
        Ok(())
    }

    async fn set_gauge(&self, name: &str, value: f64, _labels: Labels) -> ServiceResult<()> {
        let mut gauges = self.gauges.write().await;
        gauges.insert(name.to_string(), value);
        Ok(())
    }

    async fn record_histogram(&self, name: &str, value: f64, _labels: Labels) -> ServiceResult<()> {
        let mut histograms = self.histograms.write().await;
        histograms.entry(name.to_string()).or_insert_with(Vec::new).push(value);
        Ok(())
    }

    async fn get_metrics(&self) -> ServiceResult<Vec<(String, MetricType, MetricValue, Labels)>> {
        let mut metrics = Vec::new();

        // 添加计数器
        let counters = self.counters.read().await;
        for (name, value) in counters.iter() {
            metrics.push((
                name.clone(),
                MetricType::Counter,
                MetricValue::Counter(*value),
                HashMap::new(),
            ));
        }

        // 添加仪表盘
        let gauges = self.gauges.read().await;
        for (name, value) in gauges.iter() {
            metrics.push((
                name.clone(),
                MetricType::Gauge,
                MetricValue::Gauge(*value),
                HashMap::new(),
            ));
        }

        // 添加直方图
        let histograms = self.histograms.read().await;
        for (name, values) in histograms.iter() {
            if !values.is_empty() {
                let sum: f64 = values.iter().sum();
                let count = values.len() as u64;
                let buckets = vec![(1.0, count), (5.0, count), (10.0, count)]; // 简化的桶
                
                metrics.push((
                    name.clone(),
                    MetricType::Histogram,
                    MetricValue::Histogram { sum, count, buckets },
                    HashMap::new(),
                ));
            }
        }

        Ok(metrics)
    }

    async fn clear_metrics(&self) -> ServiceResult<()> {
        let mut counters = self.counters.write().await;
        let mut gauges = self.gauges.write().await;
        let mut histograms = self.histograms.write().await;
        
        counters.clear();
        gauges.clear();
        histograms.clear();
        
        Ok(())
    }
}

/// 测试环境设置
pub struct TestEnvironment {
    pub temp_dir: tempfile::TempDir,
    pub config_file: std::path::PathBuf,
}

impl TestEnvironment {
    pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
        let temp_dir = tempfile::tempdir()?;
        let config_file = temp_dir.path().join("test_config.yaml");
        
        // 创建测试配置文件
        let test_config = r#"
service:
  name: "test-service"
  version: "1.0.0"
  environment: "test"

network:
  port: 0  # 使用随机端口
  health_port: 0
  bind_address: "127.0.0.1"

monitoring:
  metrics:
    enabled: true
    port: 0
  tracing:
    enabled: true
    sampling_rate: 1.0
  logging:
    level: "debug"

components:
  registry:
    registry_type: "memory"
    endpoints: []
  load_balancer:
    strategy: "round_robin"
  circuit_breaker:
    enabled: true
    failure_threshold: 5
    timeout_duration: 60
  proxy:
    enabled: false

performance:
  connection_pool:
    max_connections: 10
    min_connections: 2
  thread_pool:
    max_threads: 4
  memory:
    max_heap_size: 134217728  # 128MB
"#;

        std::fs::write(&config_file, test_config)?;

        Ok(Self {
            temp_dir,
            config_file,
        })
    }

    pub fn config_file_path(&self) -> &std::path::Path {
        &self.config_file
    }
}

/// 等待条件满足的辅助函数
pub async fn wait_for_condition<F, Fut>(
    condition: F,
    timeout: std::time::Duration,
    interval: std::time::Duration,
) -> Result<(), Box<dyn std::error::Error>>
where
    F: Fn() -> Fut,
    Fut: std::future::Future<Output = bool>,
{
    let start = std::time::Instant::now();
    
    while start.elapsed() < timeout {
        if condition().await {
            return Ok(());
        }
        tokio::time::sleep(interval).await;
    }
    
    Err("等待条件超时".into())
}

/// 压力测试辅助函数
pub async fn run_stress_test<F, Fut>(
    name: &str,
    operation: F,
    concurrency: usize,
    duration: std::time::Duration,
) -> StressTestResult
where
    F: Fn() -> Fut + Send + Sync + 'static + Clone,
    Fut: std::future::Future<Output = Result<(), Box<dyn std::error::Error + Send + Sync>>> + Send,
{
    println!("🔥 开始压力测试: {} (并发: {}, 持续: {:?})", name, concurrency, duration);
    
    let start_time = std::time::Instant::now();
    let mut handles = Vec::new();
    let total_operations = Arc::new(std::sync::atomic::AtomicU64::new(0));
    let successful_operations = Arc::new(std::sync::atomic::AtomicU64::new(0));
    let failed_operations = Arc::new(std::sync::atomic::AtomicU64::new(0));

    // 启动并发任务
    for _ in 0..concurrency {
        let operation = operation.clone();
        let total_ops = total_operations.clone();
        let success_ops = successful_operations.clone();
        let failed_ops = failed_operations.clone();
        let test_duration = duration;

        let handle = tokio::spawn(async move {
            let task_start = std::time::Instant::now();
            
            while task_start.elapsed() < test_duration {
                total_ops.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
                
                match operation().await {
                    Ok(_) => {
                        success_ops.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
                    }
                    Err(_) => {
                        failed_ops.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
                    }
                }
            }
        });
        
        handles.push(handle);
    }

    // 等待所有任务完成
    for handle in handles {
        handle.await.unwrap();
    }

    let actual_duration = start_time.elapsed();
    let total = total_operations.load(std::sync::atomic::Ordering::Relaxed);
    let successful = successful_operations.load(std::sync::atomic::Ordering::Relaxed);
    let failed = failed_operations.load(std::sync::atomic::Ordering::Relaxed);

    let result = StressTestResult {
        name: name.to_string(),
        concurrency,
        duration: actual_duration,
        total_operations: total,
        successful_operations: successful,
        failed_operations: failed,
        operations_per_second: total as f64 / actual_duration.as_secs_f64(),
        success_rate: if total > 0 { successful as f64 / total as f64 } else { 0.0 },
    };

    println!("✅ 压力测试完成: {}", name);
    println!("   总操作数: {}", result.total_operations);
    println!("   成功: {}, 失败: {}", result.successful_operations, result.failed_operations);
    println!("   QPS: {:.2}", result.operations_per_second);
    println!("   成功率: {:.2}%", result.success_rate * 100.0);

    result
}

/// 压力测试结果
#[derive(Debug)]
pub struct StressTestResult {
    pub name: String,
    pub concurrency: usize,
    pub duration: std::time::Duration,
    pub total_operations: u64,
    pub successful_operations: u64,
    pub failed_operations: u64,
    pub operations_per_second: f64,
    pub success_rate: f64,
}